use crate::generator::GenerationContext;
use anyhow::{Context, Result};
use std::path::Path;
use tera::Tera;
use tokio::fs;

/// 文件生成器
/// 负责从模板生成具体的文件
pub struct FileGenerator {
    tera: Tera,
}

impl FileGenerator {
    /// 创建新的文件生成器
    pub fn new() -> Self {
        let mut tera = Tera::new("templates/**/*").unwrap_or_else(|e| {
            eprintln!("模板解析错误: {}", e);
            Tera::default()
        });

        // 注册自定义过滤器
        tera.register_filter("kebab_case", Self::kebab_case_filter);
        tera.register_filter("snake_case", Self::snake_case_filter);
        tera.register_filter("pascal_case", Self::pascal_case_filter);
        tera.register_filter("camel_case", Self::camel_case_filter);

        Self { tera }
    }

    /// 从模板生成文件
    pub async fn generate_from_template(
        &self,
        template_content: &str,
        output_path: &Path,
        context: &GenerationContext,
    ) -> Result<()> {
        // 渲染模板
        let rendered = self.render_template(template_content, context).with_context(|| format!("渲染模板失败: {}", output_path.display()))?;

        // 确保父目录存在
        if let Some(parent) = output_path.parent() {
            fs::create_dir_all(parent).await.with_context(|| format!("创建目录失败: {}", parent.display()))?;
        }

        // 写入文件
        fs::write(output_path, rendered).await.with_context(|| format!("写入文件失败: {}", output_path.display()))?;

        Ok(())
    }

    /// 从内置模板生成文件
    pub async fn generate_from_builtin_template(
        &self,
        template_name: &str,
        output_path: &Path,
        context: &GenerationContext,
    ) -> Result<()> {
        // 尝试从Tera实例获取模板
        let rendered =
            self.tera.render(template_name, &context.to_template_context()).with_context(|| format!("渲染内置模板失败: {}", template_name))?;

        // 确保父目录存在
        if let Some(parent) = output_path.parent() {
            fs::create_dir_all(parent).await.with_context(|| format!("创建目录失败: {}", parent.display()))?;
        }

        // 写入文件
        fs::write(output_path, rendered).await.with_context(|| format!("写入文件失败: {}", output_path.display()))?;

        Ok(())
    }

    /// 渲染模板内容
    fn render_template(
        &self,
        template_content: &str,
        context: &GenerationContext,
    ) -> Result<String> {
        let mut tera = Tera::default();

        // 注册自定义过滤器
        tera.register_filter("kebab_case", Self::kebab_case_filter);
        tera.register_filter("snake_case", Self::snake_case_filter);
        tera.register_filter("pascal_case", Self::pascal_case_filter);
        tera.register_filter("camel_case", Self::camel_case_filter);

        // 添加模板
        tera.add_raw_template("template", template_content).context("添加模板失败")?;

        // 渲染
        let rendered = tera.render("template", &context.to_template_context()).context("渲染模板失败")?;

        Ok(rendered)
    }

    /// 验证生成的文件
    pub async fn validate_generated_file(
        &self,
        path: &Path,
    ) -> Result<()> {
        if !path.exists() {
            anyhow::bail!("生成的文件不存在: {}", path.display());
        }

        let metadata = fs::metadata(path).await.with_context(|| format!("无法获取文件元数据: {}", path.display()))?;

        if metadata.len() == 0 {
            anyhow::bail!("生成的文件为空: {}", path.display());
        }

        // 如果是 Rust 文件，可以进行基本的语法检查
        if path.extension().and_then(|s| s.to_str()) == Some("rs") {
            self.validate_rust_syntax(path).await?;
        }

        Ok(())
    }

    /// 验证 Rust 文件语法
    async fn validate_rust_syntax(
        &self,
        path: &Path,
    ) -> Result<()> {
        let content = fs::read_to_string(path).await.with_context(|| format!("读取 Rust 文件失败: {}", path.display()))?;

        // 简单的语法检查：检查括号匹配
        let mut brace_count = 0;
        let mut paren_count = 0;
        let mut bracket_count = 0;

        for ch in content.chars() {
            match ch {
                '{' => brace_count += 1,
                '}' => brace_count -= 1,
                '(' => paren_count += 1,
                ')' => paren_count -= 1,
                '[' => bracket_count += 1,
                ']' => bracket_count -= 1,
                _ => {},
            }
        }

        if brace_count != 0 {
            anyhow::bail!("大括号不匹配: {}", path.display());
        }
        if paren_count != 0 {
            anyhow::bail!("小括号不匹配: {}", path.display());
        }
        if bracket_count != 0 {
            anyhow::bail!("方括号不匹配: {}", path.display());
        }

        Ok(())
    }

    /// 批量生成文件
    pub async fn batch_generate(
        &self,
        templates: Vec<(&str, &Path)>,
        context: &GenerationContext,
    ) -> Result<()> {
        for (template_content, output_path) in templates {
            self.generate_from_template(template_content, output_path, context)
                .await
                .with_context(|| format!("批量生成失败: {}", output_path.display()))?;
        }
        Ok(())
    }

    // 自定义过滤器
    fn kebab_case_filter(
        value: &tera::Value,
        _: &std::collections::HashMap<String, tera::Value>,
    ) -> tera::Result<tera::Value> {
        match value {
            tera::Value::String(s) => {
                let kebab = s.replace('_', "-").to_lowercase();
                Ok(tera::Value::String(kebab))
            },
            _ => Err(tera::Error::msg("kebab_case filter can only be applied to strings")),
        }
    }

    fn snake_case_filter(
        value: &tera::Value,
        _: &std::collections::HashMap<String, tera::Value>,
    ) -> tera::Result<tera::Value> {
        match value {
            tera::Value::String(s) => {
                let snake = s.replace('-', "_").to_lowercase();
                Ok(tera::Value::String(snake))
            },
            _ => Err(tera::Error::msg("snake_case filter can only be applied to strings")),
        }
    }

    fn pascal_case_filter(
        value: &tera::Value,
        _: &std::collections::HashMap<String, tera::Value>,
    ) -> tera::Result<tera::Value> {
        match value {
            tera::Value::String(s) => {
                let pascal = s
                    .split(&['-', '_'][..])
                    .map(|word| {
                        let mut chars = word.chars();
                        match chars.next() {
                            None => String::new(),
                            Some(first) => first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase(),
                        }
                    })
                    .collect::<String>();
                Ok(tera::Value::String(pascal))
            },
            _ => Err(tera::Error::msg("pascal_case filter can only be applied to strings")),
        }
    }

    fn camel_case_filter(
        value: &tera::Value,
        _: &std::collections::HashMap<String, tera::Value>,
    ) -> tera::Result<tera::Value> {
        match value {
            tera::Value::String(s) => {
                let parts: Vec<&str> = s.split(&['-', '_'][..]).collect();
                if parts.is_empty() {
                    return Ok(tera::Value::String(String::new()));
                }

                let mut result = parts[0].to_lowercase();
                for part in &parts[1..] {
                    let mut chars = part.chars();
                    if let Some(first) = chars.next() {
                        result.push_str(&first.to_uppercase().collect::<String>());
                        result.push_str(&chars.as_str().to_lowercase());
                    }
                }
                Ok(tera::Value::String(result))
            },
            _ => Err(tera::Error::msg("camel_case filter can only be applied to strings")),
        }
    }
}

impl Default for FileGenerator {
    fn default() -> Self {
        Self::new()
    }
}
